package memtable

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"os"
	"reflect"
	"sort"

	"gitee.com/haodreams/libs/mathx"
)

type Row struct {
	Deleted bool
	Data    []any
}

// 设置单元格指针
func (m *Row) SetCellPtr(idx int, ptr any) {
	m.Data[idx] = ptr
}

// 临时表
type TempTable struct {
	Titles []string
	nCol   int //列数
	Rows   []*Row
}

// 只有临时表才能排序排序
func (m *TempTable) OrderBy(name string, desc bool) (err error) {
	idx := -1
	for i := range m.Titles {
		if m.Titles[i] == name {
			idx = i
			break
		}
	}
	if idx < 0 {
		err = fmt.Errorf("'%s' 列不存在 SELECT 列表", name)
		return
	}
	typ := TypeUnknow

	for _, row := range m.Rows {
		cell := row.Data[idx]
		if cell == nil {
			continue
		}
		switch cell.(type) {
		case string:
			typ = TypeString
		case float64:
			typ = TypeNumber
		default:
			err = fmt.Errorf("'%s' 列数据类型错误", name)
			return
		}
	}
	if typ < 0 {
		return
	}

	if typ == TypeNumber {
		if desc {
			sort.Slice(m.Rows, func(i, j int) bool {
				x := m.Rows[i].Data[idx]
				y := m.Rows[j].Data[idx]
				if x == nil || y == nil {
					return true
				}
				x1 := x.(float64)
				y1 := y.(float64)
				return x1 > y1
			})
		} else {
			sort.Slice(m.Rows, func(i, j int) bool {
				x := m.Rows[i].Data[idx]
				y := m.Rows[j].Data[idx]
				if x == nil || y == nil {
					return true
				}
				x1 := x.(float64)
				y1 := y.(float64)
				return x1 < y1
			})
		}
	} else {
		if desc {
			sort.Slice(m.Rows, func(i, j int) bool {
				x := m.Rows[i].Data[idx]
				y := m.Rows[j].Data[idx]
				if x == nil || y == nil {
					return true
				}
				x1 := x.(string)
				y1 := y.(string)
				return x1 > y1
			})
		} else {
			sort.Slice(m.Rows, func(i, j int) bool {
				x := m.Rows[i].Data[idx]
				y := m.Rows[j].Data[idx]
				if x == nil || y == nil {
					return true
				}
				x1 := x.(string)
				y1 := y.(string)
				return x1 < y1
			})

		}
	}
	return
}

// 根据name补充数据
// 类似于sql的left key join
func (m *TempTable) FillBy(key, name string, vals []float64) (t *TempTable, err error) {
	max, _ := mathx.Max(vals)
	min, _ := mathx.Min(vals)
	step := max - min + 1
	mapRow := map[float64]*Row{}
	mapKey := map[float64]int{}
	mapVal := map[float64]bool{}
	for _, val := range vals {
		mapVal[val] = true
	}
	keyIdx := -1
	for i := range m.Titles {
		if m.Titles[i] == key {
			keyIdx = i
			break
		}
	}
	if keyIdx < 0 {
		err = fmt.Errorf("'%s' 列不存在 SELECT 列表", key)
		return
	}
	nameIdx := -1
	for i := range m.Titles {
		if m.Titles[i] == name {
			nameIdx = i
			break
		}
	}
	if nameIdx < 0 {
		err = fmt.Errorf("'%s' 列不存在 SELECT 列表", name)
		return
	}
	for _, row := range m.Rows {
		val := row.Data[keyIdx]
		if val == nil {
			continue
		}
		key := val.(float64)
		mapKey[key] = 1
		val = row.Data[nameIdx]
		if val == nil {
			continue
		}
		v := val.(float64)
		if ok := mapVal[v]; !ok {
			continue
		}
		id := key*step + v
		mapRow[id] = row
	}
	t = NewTempTable(m.Titles)
	for key := range mapKey {
		for _, v := range vals {
			id := key*step + v
			row := mapRow[id]
			if row != nil {
				t.Rows = append(t.Rows, row)
			} else {
				row = t.Append()
				row.Data[keyIdx] = key
				row.Data[nameIdx] = v
			}
		}
	}
	return t, nil
}

func (m *TempTable) Save(path string) (err error) {
	switch path {
	case "stdout":
		return m.save(bufio.NewWriter(os.Stdout))
	}
	f, err := os.Create(path)
	if err != nil {
		return
	}
	defer f.Close()
	return m.save(bufio.NewWriter(f))
}
func (m *TempTable) String() string {
	buf := bytes.NewBuffer(nil)
	m.save(bufio.NewWriter(buf))
	return buf.String()
}

// 保存临时表数据
func (m *TempTable) save(buf *bufio.Writer) (err error) {
	for i := range m.Titles {
		if i != 0 {
			err = buf.WriteByte(',')
			if err != nil {
				return err
			}
		}
		_, err = buf.WriteString(m.Titles[i])
		if err != nil {
			return err
		}
	}
	buf.WriteByte('\n')
	for _, row := range m.Rows {
		for i := range row.Data {
			if i != 0 {
				err = buf.WriteByte(',')
				if err != nil {
					return err
				}

			}
			_, err = buf.WriteString(fmt.Sprint(row.Data[i]))
			if err != nil {
				return err
			}
		}
		buf.WriteByte('\n')
	}
	buf.Flush()
	return
}

// 追加一行
func (m *TempTable) Append() *Row {
	r := new(Row)
	r.Data = make([]any, m.nCol)
	m.Rows = append(m.Rows, r)
	return r
}

// 新建一个临时表
func NewTempTable(titles []string) *TempTable {
	tt := new(TempTable)
	tt.nCol = len(titles)
	tt.Titles = titles
	return tt
}

type Table struct {
	columnIndex  map[string]int //标题所在的位置
	columnTitles []string       //列名称
	columnType   []int          //列的类型
	name         string         //表名
	regName      string         //注册后的表名

	primaryKey     string           //主键
	primaryKeyType int              //主键类型
	primaryKeyIdx  int              //主键的位置
	rows           []*Row           //数据
	mapStrRow      map[string]*Row  //主键关联的行数据
	mapNumRow      map[float64]*Row //主键关联的行数据
}

func (m *Table) GetRowByIndex(idx int) *Row {
	return m.rows[idx]
}

func (m *Table) GetRowByStrKey(key string) *Row {
	return m.mapStrRow[key]
}

func (m *Table) GetRowByNumKey(key float64) *Row {
	return m.mapNumRow[key]
}

func (m *Table) Rows() []*Row {
	return m.rows
}
func (m *Table) Titles() []string {
	return m.columnTitles
}

func (m *Table) ColumnTypes() []int {
	return m.columnType
}

func (m *Table) Name() string {
	return m.name
}

func (m *Table) RegisterName() string {
	return m.regName
}

func (m *Table) SetRegisterName(name string) {
	m.regName = name
}

func (m *Table) ColumnIndex(title string) int {
	idx, ok := m.columnIndex[title]
	if ok {
		return idx
	}
	return -1
}

func (m *Table) PrimaryKey() string {
	return m.primaryKey
}

func (m *Table) PrimaryKeyType() int {
	return m.primaryKeyType
}

func (m *Table) PrimaryKeyIndex() int {
	return m.primaryKeyIdx
}

// 添加新的列
// 列的类型智能是字符串和float64类型 TypeNumber = 0;TypeString = 1
func (m *Table) NewColums(titles []string, types []int) (err error) {
	n := len(titles)
	if n != len(types) {
		err = errors.New("列和列类型不一致")
		return
	}
	var newTitles []string
	var newTypes []int
	for i, title := range titles {
		_, ok := m.columnIndex[title]
		if ok {
			continue
		}
		newTitles = append(newTitles, title)
		newTypes = append(newTypes, types[i])
		m.columnIndex[title] = len(m.columnIndex)
	}
	n = len(newTitles)
	m.columnTitles = append(m.columnTitles, newTitles...)
	m.columnType = append(m.columnType, newTypes...)
	fields := make([]any, n)
	for _, row := range m.rows {
		row.Data = append(row.Data, fields...)
	}
	return
}

// 复制表schme
func (m *Table) CopySchema() *Table {
	t := new(Table)
	t.columnIndex = m.columnIndex
	t.primaryKey = m.primaryKey
	t.columnTitles = m.columnTitles
	t.columnType = m.columnType
	t.primaryKeyType = m.primaryKeyType
	return t
}

// 从一个数组中建立一个表
func NewTable(table any, key string) (t *Table, err error) {
	t = new(Table)
	t.primaryKey = key
	sd := NewStructDetail(table, "")
	if sd.err != nil {
		return t, sd.err
	}
	t.name = sd.Name
	t.columnIndex = make(map[string]int)
	idx := 0
	t.columnTitles = make([]string, len(sd.Columns))
	t.columnType = make([]int, len(sd.Columns))
	titleIndex := make([][]int, len(sd.Columns))
	for _, col := range sd.Columns {
		if col.Kind >= 0 {
			t.columnIndex[col.FullName] = idx
			t.columnType[idx] = col.Kind
			t.columnTitles[idx] = col.FullName
			titleIndex[idx] = col.Index
			if key == col.Name {
				t.primaryKeyType = col.Kind
				t.primaryKeyIdx = idx
			}
			idx++
		}
	}
	t.columnTitles = t.columnTitles[:idx]
	t.columnType = t.columnType[:idx]

	typ := reflect.TypeOf(table)
	if !(typ.Kind() == reflect.Slice || typ.Kind() == reflect.Array) {
		return nil, errors.New("参数错误")
	}

	list := reflect.Indirect(reflect.ValueOf(table))
	num := list.Len()
	if num == 0 {
		return
	}
	t.rows = make([]*Row, num)
	for i := 0; i < num; i++ {
		srow := list.Index(i)
		srow = reflect.Indirect(srow)
		row := new(Row)
		row.Data = make([]any, idx)
		t.rows[i] = row
		for j := 0; j < idx; j++ {
			scell, err := FieldByIndex(titleIndex[j], srow)

			switch t.columnType[j] {
			case TypeNumber:
				var pfval *float64
				if err != nil {
					row.Data[j] = pfval
					continue
				}
				fval, err := GetFloatValue(scell)
				if err == nil {
					pfval = &fval
				}
				row.Data[j] = pfval
			case TypeString:
				var pstr *string
				if err != nil {
					row.Data[j] = pstr
					continue
				}
				str := scell.String()
				row.Data[j] = &str
			}
		}
	}
	if t.primaryKeyType == TypeNumber {
		t.mapNumRow = map[float64]*Row{}
		for _, row := range t.rows {
			cell := row.Data[t.primaryKeyIdx]
			if cell == nil {
				continue
			}
			id, ok := cell.(*float64)
			if ok {
				t.mapNumRow[*id] = row
			}
		}
	} else {
		t.mapStrRow = map[string]*Row{}
		for _, row := range t.rows {
			cell := row.Data[t.primaryKeyIdx]
			if cell == nil {
				continue
			}
			id, ok := cell.(*string)
			if ok {
				t.mapStrRow[*id] = row
			}
		}
	}

	return
}

// 更新单元格的值
func (m *Table) UpdateCell(id float64, name string, fvalue float64) (err error) {
	row := m.mapNumRow[id]
	if row == nil {
		return fmt.Errorf("不存在主键: '%f'", id)
	}
	//TODO
	idx := m.ColumnIndex(name)
	if idx < 0 {
		err = fmt.Errorf("'%s' 列名不存在", name)
		return
	}
	if idx == m.primaryKeyIdx {
		err = errors.New("主键不允许修改")
		return
	}
	pcell := row.Data[idx]
	if pcell == nil {
		cell := new(float64)
		*cell = fvalue
		row.Data[idx] = cell
		return
	}
	cell, ok := pcell.(*float64)
	if ok && cell != nil {
		*cell = fvalue
	} else {
		cell := new(float64)
		*cell = fvalue
		row.Data[idx] = cell
	}

	return
}

func GetFloatValue(value reflect.Value) (b float64, err error) {
	switch value.Kind() {
	case reflect.Bool:
		if value.Bool() {
			b = 1
		} else {
			b = 0
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		b = float64(value.Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		b = float64(value.Uint())
	case reflect.Float32, reflect.Float64:
		b = float64(value.Float())
	default:
		err = errors.New("param error type")
		return
	}
	return
}

func FieldByIndex(index []int, v reflect.Value) (reflect.Value, error) {
	if len(index) == 1 {
		return v.Field(index[0]), nil
	}
	//v.m(reflect.Struct)
	for i, x := range index {
		if i > 0 {
			if v.Kind() == reflect.Pointer && v.Type().Elem().Kind() == reflect.Struct {
				if v.IsNil() {
					//panic("reflect: indirection through nil pointer to embedded struct")
					return v, errors.New("reflect: indirection through nil pointer to embedded struct")
				}
				v = v.Elem()
			}
		}
		v = v.Field(x)
	}
	return v, nil
}

func (m *Table) Save(path string) (err error) {
	switch path {
	case "stdout":
		return m.save(bufio.NewWriter(os.Stdout))
	}
	f, err := os.Create(path)
	if err != nil {
		return
	}
	defer f.Close()
	return m.save(bufio.NewWriter(f))
}
func (m *Table) String() string {
	buf := bytes.NewBuffer(nil)
	m.save(bufio.NewWriter(buf))
	return buf.String()
}

func (m *Table) save(buf *bufio.Writer) (err error) {
	for i := range m.columnTitles {
		if i != 0 {
			err = buf.WriteByte(',')
			if err != nil {
				return err
			}
		}
		_, err = buf.WriteString(m.columnTitles[i])
		if err != nil {
			return err
		}
	}
	buf.WriteByte('\n')
	for _, row := range m.rows {
		for i := range row.Data {
			if i != 0 {
				err = buf.WriteByte(',')
				if err != nil {
					return err
				}

			}
			_, err = buf.WriteString(fmt.Sprint(row.Data[i]))
			if err != nil {
				return err
			}
		}
		buf.WriteByte('\n')
	}
	buf.Flush()
	return
}
